package net.suntec.mrs.io;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

/**
 * 启动一个线程，监听指定的端口
 * 
 * @author xiaofei.xu
 * 
 */
public class IoListener implements Runnable, InitializingBean {

	/** 服务监听端口 */
	private int port = 2391;

	/** 处理对象 */
	private TCPProtocol protocol;

	/** Logger */
	private static final Logger logger = LoggerFactory.getLogger( IoListener.class );

	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.notNull( this.protocol, "Protocol must be provided" );
	}

	@Override
	public void run() {

		try {

			Selector selector = Selector.open();

			// register channel
			ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.configureBlocking( false );
			serverSocketChannel.socket().bind( new InetSocketAddress( port ) );
			serverSocketChannel.register( selector, SelectionKey.OP_ACCEPT );

			while ( true ) {
				// poll

				// select
				selector.select();

				Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
				while ( keyIterator.hasNext() ) {
					SelectionKey key = keyIterator.next();

					// Server socket channel has pending connection requests?
					if ( key.isAcceptable() ) {
						protocol.handleAccept( key );
					}
					// Client socket channel has pending data?
					if ( key.isReadable() ) {
						protocol.handleRead( key );
					}
					// Client socket channel is available for waiting and
					// key is valid
					if ( key.isValid() && key.isWritable() ) {
						protocol.handleWrite( key );
					}

					// remove from set of selected keys
					keyIterator.remove();
				}
			}
		}
		catch ( IOException e ) {
			logger.error( "Service is stoped. Caused by: " + e.getMessage() );
		}
	}

	/**
	 * 开始监听指定的端口
	 */
	public void start() {
		Thread thread = new Thread( this );
		thread.start();
	}

	/**
	 * 指定监听端口号
	 * 
	 * @param port
	 *          监听端口号
	 */
	public void setPort( int port ) {
		this.port = port;
	}

	/**
	 * 指定消息处理的协议
	 * 
	 * @param protocol
	 *          消息处理的协议
	 */
	public void setProtocol( TCPProtocol protocol ) {
		this.protocol = protocol;
	}
}
